package com.tunnel.common.tunnel;

import com.tunnel.common.constant.Constant;
import com.tunnel.common.task.BaseTask;
import com.tunnel.common.util.ByteArrayUtil;
import com.tunnel.common.util.LogUtil;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;

public class TunnelDataQueueManager {
	//ping消息
	public static final byte PING_MSG = 1;
    //注册信息
	public static final byte REGISTER_MSG = 2;
	
	//##############HTTP####################
    //HTTP数据
    public static final byte HTTP_DATA_MSG = 3;
    //停止tunnel-client的http task，这会导致tunnel中的http数据尽快停止传输，并触发浏览器与tunnel-server的连接断开
    public static final byte STOP_HTTP_TASK_MSG = 4;
    
    //#############TCP/IP##################
    //TCP建立连接信号
    public static final byte TCP_CONNECT_MSG = 5;
    //TCP数据
    public static final byte TCP_DATA_MSG = 6;
    //停止tuunel-client与app的TCP连接 
    public static final byte TCP_CLOSE_MSG = 7;

    public static TunnelDataQueue TUNNEL_DATA_QUEUE = null;
    
    public static void addBeatHeartCtx(ChannelHandlerContext ctx){
    	if(TUNNEL_DATA_QUEUE != null){
    		TUNNEL_DATA_QUEUE.addBeatHeartCtx(ctx);
    	}
    }
    
    protected static void removeBeatHeartCtx(ChannelHandlerContext ctx){
    	if(TUNNEL_DATA_QUEUE != null){
    		TUNNEL_DATA_QUEUE.removeBeatHeartCtx(ctx);
    	}
    }
    
    public static synchronized void startTunnelDataQueue(String name,boolean needBeatHeart){
    	if(TUNNEL_DATA_QUEUE == null){
    		TUNNEL_DATA_QUEUE = new TunnelDataQueue(name, needBeatHeart);
//        	LogUtil.log("startQueue");
    		TUNNEL_DATA_QUEUE.startQueue();
    	}
    }
    
    public static void commitData(byte flag,ChannelHandlerContext ctx,byte[] ...data){
    	commitData(null, flag, ctx, data);
    }
    
    public static void commitData(BaseTask task,byte flag,ChannelHandlerContext ctx,byte[] ...datas){
    	TunnelData tunnelData = new TunnelData(task,ctx,flag, datas);
		boolean addSuccess = TUNNEL_DATA_QUEUE.addDataToQueue(tunnelData);
//		LogUtil.log("commitData success:"+addSuccess);
		while(!addSuccess){
			try {
				Thread.sleep(100);
			} catch (Exception e) {}
			addSuccess = TUNNEL_DATA_QUEUE.addDataToQueue(tunnelData);
//			LogUtil.log("commitData success:"+addSuccess);
		}
    }
    
    public static void closeTunnelDataQueue(){
//    	LogUtil.log("closeQueue");
    	TUNNEL_DATA_QUEUE.stop();
    }
    
    /**
     * 禁止外部使用者
     */
    protected static void doSendData(TunnelData tunnelData){
    	try {
    		do{
    			ChannelHandlerContext ctx = tunnelData.getCtx();
	    		if(ctx.isRemoved() || !ctx.channel().isActive()){
	    			break;
	    		}
	    		
	    		if(tunnelData.getTask() != null && tunnelData.getTask().isStop()){
	    			//如果数据包是指定了来源任务的，并且来源任务已经停了，那么数据包也停止发送
	    			//及时停止
	    			break;
	    		}
	    		
	    		//包过滤，排查包中是包含内建的结尾符号，如果包含，那么会被tunnel管道分割掉，导致包破坏
	    		//理论上禁止结尾符号外用，但是一旦出现，比如nice mq的通讯包，也是用的tunnel底层
	    		//这回导致原本通讯包内，就含有结尾符号，那么在tcp转发，进入tunnel管道后，就被破坏掉了
	    		int dataLen = 0;
	    		byte[][] datas = tunnelData.getDatas();//这会导致tunnelData里的datas数据也改掉
	    		if(datas != null){
	    			for(int i=0;i<datas.length;i++){
	            		if(datas[i] != null){
	            			datas[i] = ByteArrayUtil.replace(datas[i], Constant.TUNNEL_DATA_END_FLAG_BYTES, Constant.TUNNEL_DATA_END_FLAG_CONVERT_BYTES);
	            			dataLen = dataLen+datas[i].length;
	            		}
	            	}
	    		}
            	
            	/*if(dataLen > 0){
                	LogUtil.log("tunnel send:falg["+tunnelData.getFlag()+"] size["+dataLen+"b]");
            	}*/
            	/*if(tunnelData.getFlag() == PING_MSG){
            		break;
//            		LogUtil.log("beat heart");
            	}*/
            	
            	
            	ByteBuf buf = Unpooled.buffer(1+dataLen+Constant.TUNNEL_DATA_END_FLAG_BYTES.length);  
                buf.writeByte(tunnelData.getFlag());//发送一个数据标识位
	    		if(datas != null){
	    			for(byte[] oneData:datas){
	                	if(oneData != null){
//		                	LogUtil.log("tunnel send:"+new String(dataOne));
	                		buf.writeBytes(oneData);//发送数据
	                	}
	                }
	    		}
                
                buf.writeBytes(Constant.TUNNEL_DATA_END_FLAG_BYTES);//发送结束标识
                
                //netty channel里发送数据是都堆在堆内存里的，空间限制，因此如果写的太快，能回oom
                int waiteMs = 1;
                while(!ctx.channel().isWritable()){
                	try {
                		Thread.sleep(waiteMs);
					} catch (Exception e) {}
                	waiteMs = waiteMs+1;
                }
                
                ctx.writeAndFlush(buf);
    		}while(false);
		} catch (Exception e) {
			LogUtil.error(e);
		}
    }
    
}
